/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.neuralstudio.utils;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.jane.core.TransferFunctions;
import org.jane.core.functions.LogSigmoidFunction;
import org.jane.core.functions.TanhFunction;
import org.jane.core.layers.SimpleLayer;
import org.jane.core.networks.AbstractNeuralNetwork;
import org.jane.core.networks.Adaline;
import org.jane.core.networks.CompetitiveNetwork;
import org.jane.core.networks.MultiLayerPerceptron;
import org.jane.core.networks.Perceptron;
import org.jane.utils.AbstractDataset;
import org.jane.utils.SupervisedDataset;
import org.jane.utils.UnsupervisedDataset;
import org.nfunk.jep.JEP;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 *
 * @author william
 */
public class Utils {

    public static String listToCSV(List list) {
        StringBuffer sb = new StringBuffer();
        int i = 0;
        for (Object o : list) {
            if (i != 0) 
                sb.append(",");
            sb.append(o.toString());
            i++;
        }
        return sb.toString();
    }

     public static List csvToArrayList(String csv) {
        List list = new ArrayList();
        String[] array = csv.split(",");

        for (String s : array) {
            list.add(Float.parseFloat(s));
        }
        return list;
    }

     public static Float[] getValuesInRange(float min,float max,float inc) {
         List<Float> values = new ArrayList<Float>();
         float currentValue = min;
         while (currentValue <= max) {
             values.add(currentValue);
             currentValue = currentValue + inc;
         }
         return values.toArray(new Float[values.size()]);
     }

    public static List<List<List<Float>>> getDatasetFromFunction(String function, Float[] valuesInRange) throws Exception {
        List<List<List<Float>>> dataset = new ArrayList<List<List<Float>>>();
        JEP functionParser = new JEP();
        functionParser.addStandardConstants();
        functionParser.addStandardFunctions();
        functionParser.addVariable("x",0);
        functionParser.setImplicitMul(true);
        functionParser.parseExpression(function);
        for(Float value : valuesInRange) {
            ArrayList<List<Float>> temp = new ArrayList<List<Float>>();
            ArrayList<Float> inputs = new ArrayList<Float>();
            ArrayList<Float> outputs = new ArrayList<Float>();
            inputs.add(value);
            functionParser.setVarValue("x", value);
            if (Double.isNaN(functionParser.getValue())) {
                throw new Exception("Error en los valores");
            }
            outputs.add((float)functionParser.getValue());
            temp.add(inputs);
            temp.add(outputs);
            dataset.add(temp);
        }
        return dataset;
    }

    public static double[] getDoubleValuesInRange(float min, float max, float inc) {
        int size =  Math.round((max - min)/inc);
        double[] values = new double[size];
         double currentValue = min;
         int i = 0;
         while (currentValue <= max) {
            values[i] = currentValue;
             currentValue = currentValue + inc;
             i++;
         }
         return values;
    }

    public static double[] getValuesFromFunction(String function, double[] x, float f) {
        JEP functionParser = new JEP();
        functionParser.addStandardConstants();
        functionParser.addStandardFunctions();
        functionParser.addVariable("x",0);
        functionParser.setImplicitMul(true);
        functionParser.parseExpression(function);
        double[] y = new double[x.length];
        for (int i = 0; i < x.length; i++) {
            //functionParser.setVarValue("x", x[i]);
            y[i] = Utils.getValueFromFunction(function, x[i]);
        }
        return y;
    }

    public static double getValueFromFunction(String function, double x) {
        JEP functionParser = new JEP();
        functionParser.addStandardConstants();
        functionParser.addStandardFunctions();
        functionParser.addVariable("x",0);
        functionParser.setImplicitMul(true);
        functionParser.parseExpression(function);
        functionParser.setVarValue("x", x);
        return functionParser.getValue();
    }

    public static List<double[]> getArraysFromDataset(List<List<List<Float>>> dataset) {
        double[] x = new double[dataset.size()];
        double[] y = new double[dataset.size()];
        int i = 0;
        for(List<List<Float>> data : dataset) {
            x[i] = data.get(0).get(0);
            y[i] = data.get(1).get(0);
            i++;
        }
        List<double[]> list = new ArrayList<double[]>(2);
        list.add(x);
        list.add(y);
        return list;
    }

     public static AbstractDataset getDatasetFromXmlFile(File file) {
        SAXParserFactory spf = SAXParserFactory.newInstance();
        try {
            spf.setValidating(false);
            SAXParser sp = spf.newSAXParser();
            InputSource input = new InputSource(new FileReader(file));
            DatasetSaxHandler handler = new DatasetSaxHandler();
            sp.parse(input, handler);
            return handler.getDataset();
        } catch (ParserConfigurationException ex) {
            Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SAXException ex) {
            Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FileNotFoundException ex) {

        }catch(IOException ex){

        }
        return null;
    }
    public static void datasetToXmlFile(AbstractDataset dataset, String datasetName) {
        StringBuffer sb = new StringBuffer();
        String sep = System.getProperty("line.separator");
        sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        sb.append(sep);
        sb.append("<dataset nombre='"+datasetName+"' type = '"+(dataset instanceof SupervisedDataset?"supervised":"unsupervised")+"'>");
        sb.append(System.getProperty("line.separator"));
        if (dataset instanceof SupervisedDataset) {
            for (List<List<Float>> row : ((SupervisedDataset)dataset).getData()) {
                sb.append("<row>"+sep);
                sb.append("<input>"+sep);
                for(Float value : row.get(0)) {
                    sb.append("<value>"+value+"</value>"+sep);
                }
                sb.append("</input>"+sep);
                sb.append("<output>"+sep);
                for(Float value : row.get(1)) {
                    sb.append("<value>"+value+"</value>"+sep);
                }
                sb.append("</output>"+sep);
                sb.append("</row>"+sep);
            }

        }else{
            for (List<Float> row : ((UnsupervisedDataset)dataset).getData()) {
                sb.append("<row>"+sep);
                for(Float value : row) {
                    sb.append("<value>"+value+"</value>"+sep);
                }
                sb.append("</row>"+sep);
            }


        }
        sb.append("</dataset>");
        try {
            BufferedWriter bf = new BufferedWriter(new FileWriter(new File(datasetName + ".xml")));
            bf.write(sb.toString());
            bf.close();
        } catch (IOException ex) {

        }

    }
    public static AbstractNeuralNetwork xmlToNetwork(File file) {
       SAXParserFactory spf = SAXParserFactory.newInstance();
        try {
            spf.setValidating(false);
            SAXParser sp = spf.newSAXParser();
            InputSource input = new InputSource(new FileReader(file));
            NeuralSaxHandler handler = new NeuralSaxHandler();
            sp.parse(input, handler);
            return handler.getNetwork();
        }catch(Exception e){}
        return null;
    }
    public static void networkToXml(AbstractNeuralNetwork net, String path) {
        StringBuffer sb = new StringBuffer();
        String sep = System.getProperty("line.separator");
        sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        sb.append(sep);
        if (net instanceof Perceptron) {
            sb.append("<network type='perceptron' learningrate=''>");
            sb.append(sep);
            sb.append("<layer type='hardlimit'>");
            sb.append(sep);
            SimpleLayer sl = ((Perceptron)net).getNeurons();
            for(int i = 0; i < sl.getSize(); i++) {
                sb.append("<neuron sensitivity='"+sl.getNeuron(i).getSensitivity()+"' bias='"+sl.getNeuron(i).getBias()+"'>");
                sb.append(sep);
                for(Float w : sl.getNeuron(i).getWeights()) {
                    sb.append("<weight>");
                    sb.append(w);
                    sb.append("</weight>");
                    sb.append(sep);
                }
                sb.append("</neuron>");
            }
            sb.append("</layer>");
            sb.append(sep);
        }
        if (net instanceof Adaline) {
            sb.append("<network type='adaline' learningrate='"+((Adaline)net).getLearningRate()+"'>");
            sb.append(sep);
            sb.append("<layer type='purelin'>");
            sb.append(sep);
            SimpleLayer sl = ((Adaline)net).getNeurons();
            for(int i = 0; i < sl.getSize(); i++) {
                sb.append("<neuron sensitivity='"+sl.getNeuron(i).getSensitivity()+"' bias='"+sl.getNeuron(i).getBias()+"'>");
                sb.append(sep);
                for(Float w : sl.getNeuron(i).getWeights()) {
                    sb.append("<weight>");
                    sb.append(w);
                    sb.append("</weight>");
                    sb.append(sep);
                }
                sb.append("</neuron>");

            }
            sb.append("</layer>");
            sb.append(sep);
        }
        if (net instanceof MultiLayerPerceptron) {
            sb.append("<network type='mperceptron' learningrate='"+((MultiLayerPerceptron)net).getLearningRate()+"'>");
            sb.append(sep);
            List<SimpleLayer> sl = ((MultiLayerPerceptron)net).getNeurons();
            for(SimpleLayer l : sl) {
                String type = (l.getNeuron(0).getTransferFunctionObject() instanceof LogSigmoidFunction)?"logsigmoid":(l.getNeuron(0).getTransferFunctionObject() instanceof TanhFunction)?"tanh":"purelin";
                sb.append("<layer type='"+type+"'>");
                sb.append(sep);
                for (int i = 0; i < l.getSize(); i++) {
                    sb.append("<neuron sensitivity='"+l.getNeuron(i).getSensitivity()+"' bias='"+l.getNeuron(i).getBias()+"'>");
                    sb.append(sep);
                    for(Float w : l.getNeuron(i).getWeights()) {
                        sb.append("<weight>");
                        sb.append(w);
                        sb.append("</weight>");
                        sb.append(sep);
                    }
                    sb.append("</neuron>");
                    sb.append(sep);
                }
                sb.append("</layer>");
                sb.append(sep);
            }
        }
        if (net instanceof CompetitiveNetwork) {
            sb.append("<network type='competitive' learningrate='"+((CompetitiveNetwork)net).getLearningRate()+"'>");
            sb.append(sep);
            sb.append("<layer type='purelin'>");
            sb.append(sep);
            SimpleLayer l = (SimpleLayer)((CompetitiveNetwork)net).getNeurons().get(0);
            for (int i = 0; i < l.getSize(); i++) {
                sb.append("<neuron sensitivity='"+l.getNeuron(i).getSensitivity()+"' bias='"+l.getNeuron(i).getBias()+"'>");
                    sb.append(sep);
                    for(Float w : l.getNeuron(i).getWeights()) {
                        sb.append("<weight>");
                        sb.append(w);
                        sb.append("</weight>");
                        sb.append(sep);
                    }
                    sb.append("</neuron>");
            }
            sb.append("</layer>");
            sb.append(sep);
            sb.append("<layer type='poslin'>");
            sb.append(sep);
            l = (SimpleLayer)((CompetitiveNetwork)net).getNeurons().get(1);
            for (int i = 0; i < l.getSize(); i++) {
                sb.append("<neuron sensitivity='"+l.getNeuron(i).getSensitivity()+"' bias='"+l.getNeuron(i).getBias()+"'>");
                    sb.append(sep);
                    for(Float w : l.getNeuron(i).getWeights()) {
                        sb.append("<weight>");
                        sb.append(w);
                        sb.append("</weight>");
                        sb.append(sep);
                    }
                    sb.append("</neuron>");
            }
            sb.append("</layer>");
            sb.append(sep);
        }
        sb.append("</network>");
        try {
            if (!path.endsWith(".nsxml")) {
                path = path+".nsxml";
            }
            BufferedWriter bf = new BufferedWriter(new FileWriter(new File(path)));
            bf.write(sb.toString());
            bf.close();
        } catch (IOException ex) {

        }
    }


}
